﻿/*
Configuration Server
 
Provides a single configuration point for the several instances (development, 
staging, testing, production, etc.) for web sites
 
Includes ideas and code from all over the internet. Specially, stacktrace, msdn, github.
 
Copyright (C) 2014 by Jaime Espinosa <jaimeespinosa60@gmail.com>
 
The MIT License (MIT)

Copyright (c) 2014 jaime espinosa

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

  @author Jaime Espinosa <jaimeespinosa60@gmail.com>
  @package configuracion
  @version 0.1
*/
using Configuracion.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Data.Entity;
using ConfigurationServer.AppCode.Utilities;

namespace Configuracion.Controllers
{
    public class statsController : baseController
    {
        public class data
        {
            public string keyName { get; set; }
            public string setName { get; set; }
            public string bundleName { get; set; }
            public int bundleID { get; set; }
            public int intYear { get; set; }
            public int intMonth { get; set; }
            public int intDay { get; set; }
            public int intHour { get; set; }
        }
        [Authorize]
        public ActionResult Index(int bundleID = 0)
        {
            ViewBag.Exception = "";
            string strUserName = "";

            List<int> bundleIDs = default(List<int>);
            mdlBundle bundle = default(mdlBundle);

            try
            {
                if (User.Identity.IsAuthenticated)
                    strUserName = User.Identity.Name;

                bundleIDs = (from p in dbContext.Owners.Where(p => p.users.Any(u => u.userName == strUserName))
                                 .SelectMany(p => p.bundles)
                             select p.ID).ToList<int>();

                if (bundleIDs.Contains(bundleID))
                {
                    bundle = (from p in dbContext.Bundles
                                    .Include(p => p.Keys)
                                    .Include(p => p.Sets)
                              where p.ID == bundleID
                              select p).FirstOrDefault<mdlBundle>();
                }

                if (bundle != null)
                {
                    prepareStats(bundle.ID);
                    return View(bundle);
                }
                else
                    throw new Exception("Bundle not found");
            }
            catch (Exception ex)
            {
                throw new Exception(infoExcepcion(ex));
            }
        }
        [Authorize]
        public ActionResult hourly(int bundleID = 0, int keyID = 0, int setID = 0, int intStartHour = 0, int intEndHour = 24)
        {
            int intDay = DateTime.Now.Day;
            int intMonth = DateTime.Now.Month;
            int intYear = DateTime.Now.Year;
            string strUserName = "";
            data bundledData = null;
            IQueryable<mdlHitTestHour> statsData = null;
            List<int> bundleIDs = default(List<int>);

            try
            {
                if (bundleID == 0)
                    throw new Exception("invalid parameters");

                if (User.Identity.IsAuthenticated)
                    strUserName = User.Identity.Name;

                bundleIDs = (from p in dbContext.Owners.Where(p => p.users.Any(u => u.userName == strUserName))
                                 .SelectMany(p => p.bundles)
                             select p.ID).ToList<int>();

                if (!bundleIDs.Contains(bundleID))
                    throw new Exception("Bundle not found");

                // if only key is provided, shows the key for all sets
                if (setID == 0 & keyID > 0)
                {
                    // VERIFIES OWNERSHIP OF THE REQUESTED KEY
                    bundledData = (from p in dbContext.Bundles
                                   where p.ID == bundleID
                                   && p.Keys.Any(key => key.ID == keyID)
                                   select new data
                                     {
                                         bundleID = p.ID,
                                         bundleName = p.name,
                                         keyName = p.Keys.Where(key => key.ID == keyID).FirstOrDefault<mdlBundleKey>().name
                                     }).FirstOrDefault<data>();

                    // if key or set does not match or does not belong to the user
                    if (bundledData == null)
                        throw new Exception("Invalid parameters");
                    else
                        bundledData.setName = "All sets";

                    statsData = from hitTest in dbContext.hitTestHour.Include(p => p.Set)
                                where hitTest.Key.ID == keyID
                                & hitTest.Year == intYear
                                & hitTest.Month == intMonth
                                & hitTest.Day == intDay
                                & hitTest.Hour >= intStartHour & hitTest.Hour < intEndHour
                                select hitTest;
                }

                // if only set is provided, shows all keys for the set
                if (setID > 0 & keyID == 0)
                {
                    // VERIFIES OWNERSHIP OF THE REQUESTED SET
                    bundledData = (from p in dbContext.Bundles
                                   where p.ID == bundleID
                                   && p.Sets.Any(set => set.ID == setID)
                                   select new data
                                   {
                                       bundleID = p.ID,
                                       bundleName = p.name,
                                       setName = p.Sets.Where(set => set.ID == setID).FirstOrDefault<mdlBundleSet>().name
                                   }).FirstOrDefault<data>();

                    // if key or set does not match or does not belong to the user
                    if (bundledData == null)
                        throw new Exception("Invalid parameters");
                    else
                        bundledData.keyName = "All keys";

                    statsData = from hitTest in dbContext.hitTestHour.Include(p => p.Key)
                                where hitTest.Set.ID == setID
                                & hitTest.Year == intYear
                                & hitTest.Month == intMonth
                                & hitTest.Day == intDay
                                & hitTest.Hour >= intStartHour & hitTest.Hour < intEndHour
                                select hitTest;
                }

                // big else
                if (statsData == null) // not set yet
                {
                    // VERIFIES OWNERSHIP OF THE REQUESTED PAIR
                    bundledData = (from p in dbContext.Bundles
                                   where p.ID == bundleID
                                   && p.Keys.Any(key => key.ID == keyID) && p.Sets.Any(set => set.ID == setID)
                                   select new data
                                   {
                                       bundleID = p.ID,
                                       bundleName = p.name,
                                       setName = p.Sets.Where(set => set.ID == setID).FirstOrDefault<mdlBundleSet>().name,
                                       keyName = p.Keys.Where(key => key.ID == keyID).FirstOrDefault<mdlBundleKey>().name
                                   }).FirstOrDefault<data>();

                    // if key or set does not match or does not belong to the user
                    if (bundledData == null)
                        throw new Exception("Invalid parameters");

                    // if both are provided return stats for the pair
                    statsData = from hitTest in dbContext.hitTestHour
                                                        .Include(p => p.Set)
                                                        .Include(p => p.Key)
                                where hitTest.Key.ID == keyID
                                & hitTest.Set.ID == setID
                                & hitTest.Year == intYear
                                & hitTest.Month == intMonth
                                & hitTest.Day == intDay
                                & hitTest.Hour >= intStartHour & hitTest.Hour < intEndHour
                                select hitTest;
                }

                bundledData.intYear = intYear;
                bundledData.intMonth = intMonth;
                bundledData.intDay = intDay;
                bundledData.intHour = 0;

                ViewBag.data = bundledData;

                return View(statsData);
            }
            catch (Exception ex)
            {
                throw new Exception(infoExcepcion(ex));
            }
        }
        [Authorize]
        public ActionResult daily(int bundleID = 0, int keyID = 0, int setID = 0, int startDay = 0, int endDay = 31)
        {
            int intMonth = DateTime.Now.Month;
            int intYear = DateTime.Now.Year;
            string strUserName = "";
            data bundledData = null;
            IQueryable<mdlHitTestDay> statsData = null;
            List<int> bundleIDs = default(List<int>);

            try
            {
                if (bundleID == 0)
                    throw new Exception("invalid parameters");

                if (User.Identity.IsAuthenticated)
                    strUserName = User.Identity.Name;

                bundleIDs = (from p in dbContext.Owners.Where(p => p.users.Any(u => u.userName == strUserName))
                                 .SelectMany(p => p.bundles)
                             select p.ID).ToList<int>();

                if (!bundleIDs.Contains(bundleID))
                    throw new Exception("Bundle not found");

                // if only key is provided, shows the key for all sets
                if (setID == 0 & keyID > 0)
                {
                    // VERIFIES OWNERSHIP OF THE REQUESTED KEY
                    bundledData = (from p in dbContext.Bundles
                                   where p.ID == bundleID
                                   && p.Keys.Any(key => key.ID == keyID)
                                   select new data
                                   {
                                       bundleID = p.ID,
                                       bundleName = p.name,
                                       keyName = p.Keys.Where(key => key.ID == keyID).FirstOrDefault<mdlBundleKey>().name
                                   }).FirstOrDefault<data>();

                    // if key or set does not match or does not belong to the user
                    if (bundledData == null)
                        throw new Exception("Invalid parameters");
                    else
                        bundledData.setName = "All sets";

                    statsData = from hitTest in dbContext.hitTestDay.Include(p => p.Set)
                                where hitTest.Key.ID == keyID
                                & hitTest.Year == intYear
                                & hitTest.Month == intMonth
                                & hitTest.Day >= startDay & hitTest.Day < endDay
                                select hitTest;
                }

                // if only set is provided, shows all keys for the set
                if (setID > 0 & keyID == 0)
                {
                    // VERIFIES OWNERSHIP OF THE REQUESTED SET
                    bundledData = (from p in dbContext.Bundles
                                   where p.ID == bundleID
                                   && p.Sets.Any(set => set.ID == setID)
                                   select new data
                                   {
                                       bundleID = p.ID,
                                       bundleName = p.name,
                                       setName = p.Sets.Where(set => set.ID == setID).FirstOrDefault<mdlBundleSet>().name
                                   }).FirstOrDefault<data>();

                    // if key or set does not match or does not belong to the user
                    if (bundledData == null)
                        throw new Exception("Invalid parameters");
                    else
                        bundledData.keyName = "All keys";

                    statsData = from hitTest in dbContext.hitTestDay.Include(p => p.Key)
                                where hitTest.Set.ID == setID
                                & hitTest.Year == intYear
                                & hitTest.Month == intMonth
                                & hitTest.Day >= startDay & hitTest.Day < endDay
                                select hitTest;
                }

                // big else
                if (statsData == null) // not set yet
                {
                    // VERIFIES OWNERSHIP OF THE REQUESTED PAIR
                    bundledData = (from p in dbContext.Bundles
                                   where p.ID == bundleID
                                   && p.Keys.Any(key => key.ID == keyID) && p.Sets.Any(set => set.ID == setID)
                                   select new data
                                   {
                                       bundleID = p.ID,
                                       bundleName = p.name,
                                       setName = p.Sets.Where(set => set.ID == setID).FirstOrDefault<mdlBundleSet>().name,
                                       keyName = p.Keys.Where(key => key.ID == keyID).FirstOrDefault<mdlBundleKey>().name
                                   }).FirstOrDefault<data>();

                    // if key or set does not match or does not belong to the user
                    if (bundledData == null)
                        throw new Exception("Invalid parameters");

                    // if both are provided return stats for the pair
                    statsData = from hitTest in dbContext.hitTestDay
                                                        .Include(p => p.Set)
                                                        .Include(p => p.Key)
                                where hitTest.Key.ID == keyID
                                & hitTest.Set.ID == setID
                                & hitTest.Year == intYear
                                & hitTest.Month == intMonth
                                & hitTest.Day >= startDay & hitTest.Day < endDay
                                select hitTest;
                }

                bundledData.intYear = intYear;
                bundledData.intMonth = intMonth;
                bundledData.intHour = 0;

                ViewBag.data = bundledData;

                return View(statsData);
            }
            catch (Exception ex)
            {
                throw new Exception(infoExcepcion(ex));
            }
        }
        [Authorize]
        public ActionResult monthly(int bundleID = 0, int keyID = 0, int setID = 0, int startMonth = 0, int endMonth = 12)
        {
            int intMonth = DateTime.Now.Month;
            int intYear = DateTime.Now.Year;
            string strUserName = "";
            data bundledData = null;
            IQueryable<mdlHitTestMonth> statsData = null;
            List<int> bundleIDs = default(List<int>);

            try
            {
                if (bundleID == 0)
                    throw new Exception("invalid parameters");

                if (User.Identity.IsAuthenticated)
                    strUserName = User.Identity.Name;

                bundleIDs = (from p in dbContext.Owners.Where(p => p.users.Any(u => u.userName == strUserName))
                                 .SelectMany(p => p.bundles)
                             select p.ID).ToList<int>();

                if (!bundleIDs.Contains(bundleID))
                    throw new Exception("Bundle not found");

                // if only key is provided, shows the key for all sets
                if (setID == 0 & keyID > 0)
                {
                    // VERIFIES OWNERSHIP OF THE REQUESTED KEY
                    bundledData = (from p in dbContext.Bundles
                                   where p.ID == bundleID
                                   && p.Keys.Any(key => key.ID == keyID)
                                   select new data
                                   {
                                       bundleID = p.ID,
                                       bundleName = p.name,
                                       keyName = p.Keys.Where(key => key.ID == keyID).FirstOrDefault<mdlBundleKey>().name
                                   }).FirstOrDefault<data>();

                    // if key or set does not match or does not belong to the user
                    if (bundledData == null)
                        throw new Exception("Invalid parameters");
                    else
                        bundledData.setName = "All sets";

                    statsData = from hitTest in dbContext.hitTestMonth.Include(p => p.Set)
                                where hitTest.Key.ID == keyID
                                & hitTest.Year == intYear
                                & hitTest.Month >= startMonth & hitTest.Month < endMonth
                                select hitTest;
                }

                // if only set is provided, shows all keys for the set
                if (setID > 0 & keyID == 0)
                {
                    // VERIFIES OWNERSHIP OF THE REQUESTED SET
                    bundledData = (from p in dbContext.Bundles
                                   where p.ID == bundleID
                                   && p.Sets.Any(set => set.ID == setID)
                                   select new data
                                   {
                                       bundleID = p.ID,
                                       bundleName = p.name,
                                       setName = p.Sets.Where(set => set.ID == setID).FirstOrDefault<mdlBundleSet>().name
                                   }).FirstOrDefault<data>();

                    // if key or set does not match or does not belong to the user
                    if (bundledData == null)
                        throw new Exception("Invalid parameters");
                    else
                        bundledData.keyName = "All keys";

                    statsData = from hitTest in dbContext.hitTestMonth.Include(p => p.Key)
                                where hitTest.Set.ID == setID
                                & hitTest.Year == intYear
                                & hitTest.Month >= startMonth & hitTest.Month < endMonth
                                select hitTest;
                }

                // big else
                if (statsData == null) // not set yet
                {
                    // VERIFIES OWNERSHIP OF THE REQUESTED PAIR
                    bundledData = (from p in dbContext.Bundles
                                   where p.ID == bundleID
                                   && p.Keys.Any(key => key.ID == keyID) && p.Sets.Any(set => set.ID == setID)
                                   select new data
                                   {
                                       bundleID = p.ID,
                                       bundleName = p.name,
                                       setName = p.Sets.Where(set => set.ID == setID).FirstOrDefault<mdlBundleSet>().name,
                                       keyName = p.Keys.Where(key => key.ID == keyID).FirstOrDefault<mdlBundleKey>().name
                                   }).FirstOrDefault<data>();

                    // if key or set does not match or does not belong to the user
                    if (bundledData == null)
                        throw new Exception("Invalid parameters");

                    // if both are provided return stats for the pair
                    statsData = from hitTest in dbContext.hitTestMonth
                                                        .Include(p => p.Set)
                                                        .Include(p => p.Key)
                                where hitTest.Key.ID == keyID
                                & hitTest.Set.ID == setID
                                & hitTest.Year == intYear
                                & hitTest.Month >= startMonth & hitTest.Month < endMonth
                                select hitTest;
                }

                bundledData.intYear = intYear;

                ViewBag.data = bundledData;

                return View(statsData);
            }
            catch (Exception ex)
            {
                throw new Exception(infoExcepcion(ex));
            }
        }
        [Authorize]
        public ActionResult yearly(int bundleID = 0, int keyID = 0, int setID = 0, int startYear = 2014, int endYear = 2114)
        {
            int intMonth = DateTime.Now.Month;
            int intYear = DateTime.Now.Year;
            string strUserName = "";
            data bundledData = null;
            IQueryable<mdlHitTestYear> statsData = null;
            List<int> bundleIDs = default(List<int>);

            try
            {
                if (bundleID == 0)
                    throw new Exception("invalid parameters");

                if (User.Identity.IsAuthenticated)
                    strUserName = User.Identity.Name;

                bundleIDs = (from p in dbContext.Owners.Where(p => p.users.Any(u => u.userName == strUserName))
                                 .SelectMany(p => p.bundles)
                             select p.ID).ToList<int>();

                if (!bundleIDs.Contains(bundleID))
                    throw new Exception("Bundle not found");

                // if only key is provided, shows the key for all sets
                if (setID == 0 & keyID > 0)
                {
                    // VERIFIES OWNERSHIP OF THE REQUESTED KEY
                    bundledData = (from p in dbContext.Bundles
                                   where p.ID == bundleID
                                   && p.Keys.Any(key => key.ID == keyID)
                                   select new data
                                   {
                                       bundleID = p.ID,
                                       bundleName = p.name,
                                       keyName = p.Keys.Where(key => key.ID == keyID).FirstOrDefault<mdlBundleKey>().name
                                   }).FirstOrDefault<data>();

                    // if key or set does not match or does not belong to the user
                    if (bundledData == null)
                        throw new Exception("Invalid parameters");
                    else
                        bundledData.setName = "All sets";

                    statsData = from hitTest in dbContext.hitTestYear.Include(p => p.Set)
                                where hitTest.Key.ID == keyID
                                & hitTest.Year >= startYear & hitTest.Year < endYear
                                select hitTest;
                }

                // if only set is provided, shows all keys for the set
                if (setID > 0 & keyID == 0)
                {
                    // VERIFIES OWNERSHIP OF THE REQUESTED SET
                    bundledData = (from p in dbContext.Bundles
                                   where p.ID == bundleID
                                   && p.Sets.Any(set => set.ID == setID)
                                   select new data
                                   {
                                       bundleID = p.ID,
                                       bundleName = p.name,
                                       setName = p.Sets.Where(set => set.ID == setID).FirstOrDefault<mdlBundleSet>().name
                                   }).FirstOrDefault<data>();

                    // if key or set does not match or does not belong to the user
                    if (bundledData == null)
                        throw new Exception("Invalid parameters");
                    else
                        bundledData.keyName = "All keys";

                    statsData = from hitTest in dbContext.hitTestYear.Include(p => p.Key)
                                where hitTest.Set.ID == setID
                                & hitTest.Year >= startYear & hitTest.Year < endYear
                                select hitTest;
                }

                // big else
                if (statsData == null) // not set yet
                {
                    // VERIFIES OWNERSHIP OF THE REQUESTED PAIR
                    bundledData = (from p in dbContext.Bundles
                                   where p.ID == bundleID
                                   && p.Keys.Any(key => key.ID == keyID) && p.Sets.Any(set => set.ID == setID)
                                   select new data
                                   {
                                       bundleID = p.ID,
                                       bundleName = p.name,
                                       setName = p.Sets.Where(set => set.ID == setID).FirstOrDefault<mdlBundleSet>().name,
                                       keyName = p.Keys.Where(key => key.ID == keyID).FirstOrDefault<mdlBundleKey>().name
                                   }).FirstOrDefault<data>();

                    // if key or set does not match or does not belong to the user
                    if (bundledData == null)
                        throw new Exception("Invalid parameters");

                    // if both are provided return stats for the pair
                    statsData = from hitTest in dbContext.hitTestYear
                                                        .Include(p => p.Set)
                                                        .Include(p => p.Key)
                                where hitTest.Key.ID == keyID
                                & hitTest.Set.ID == setID
                                & hitTest.Year >= startYear & hitTest.Year < endYear
                                select hitTest;
                }


                ViewBag.data = bundledData;

                return View(statsData);
            }
            catch (Exception ex)
            {
                throw new Exception(infoExcepcion(ex));
            }
        }

        private void prepareStats(int bundleID = 0)
        {
            int inthour = DateTime.Now.Hour;
            int intDay = DateTime.Now.Day;
            int intMonth = DateTime.Now.Month;
            int intYear = DateTime.Now.Year;
            string strUserName = "";
            data bundledData = new data();

            List<int> bundleIDs = default(List<int>);
            List<int> bundleSets = default(List<int>);
            List<int> bundleKeys = default(List<int>);

            try
            {
                if (bundleID == 0)
                    throw new Exception("invalid parameters");

                if (User.Identity.IsAuthenticated)
                    strUserName = User.Identity.Name;

                bundleIDs = (from p in dbContext.Owners.Where(p => p.users.Any(u => u.userName == strUserName))
                                 .SelectMany(p => p.bundles)
                             select p.ID).ToList<int>();

                if (!bundleIDs.Contains(bundleID))
                    throw new Exception("Bundle not found");
                else
                {
                    bundleSets = (from p in dbContext.Bundles
                                 .Where(p => p.ID == bundleID)
                                 .SelectMany(p => p.Sets)
                                  select p.ID).ToList<int>();
                    bundleKeys = (from p in dbContext.Bundles
                                 .Where(p => p.ID == bundleID)
                                 .SelectMany(p => p.Keys)
                                  select p.ID).ToList<int>();
                }

                ViewBag.thisHour = (from hitTest in dbContext.hitTestHour
                                                        .Include(p => p.Set)
                                                        .Include(p => p.Key)
                                    where bundleKeys.Contains(hitTest.Key.ID)
                                    && bundleSets.Contains(hitTest.Set.ID)
                                    && hitTest.Year == intYear
                                    && hitTest.Month == intMonth
                                    && hitTest.Day == intDay
                                    && hitTest.Hour == inthour
                                    select hitTest).ToDictionary(p => p.Set.ID.ToString() + ":" + p.Key.ID.ToString(),
                                                      p => p.HourHits);

                ViewBag.thisDay = (from hitTest in dbContext.hitTestDay
                                        .Include(p => p.Set)
                                        .Include(p => p.Key)
                                    where bundleKeys.Contains(hitTest.Key.ID)
                                    && bundleSets.Contains(hitTest.Set.ID)
                                    && hitTest.Year == intYear
                                    && hitTest.Month == intMonth
                                    && hitTest.Day == intDay
                                   select hitTest).ToDictionary(p => p.Set.ID.ToString() + ":" + p.Key.ID.ToString(),
                                                      p => p.DayHits);

                ViewBag.thisMonth = (from hitTest in dbContext.hitTestMonth
                                     .Include(p => p.Set)
                                     .Include(p => p.Key)
                                     where bundleKeys.Contains(hitTest.Key.ID)
                                     && bundleSets.Contains(hitTest.Set.ID)
                                     && hitTest.Year == intYear
                                     && hitTest.Month == intMonth
                                     select hitTest).ToDictionary(p => p.Set.ID.ToString() + ":" + p.Key.ID.ToString(),
                                                      p => p.MonthHits);

                ViewBag.thisYear = (from hitTest in dbContext.hitTestYear
                                   .Include(p => p.Set)
                                   .Include(p => p.Key)
                                    where bundleKeys.Contains(hitTest.Key.ID)
                                    && bundleSets.Contains(hitTest.Set.ID)
                                    && hitTest.Year == intYear
                                    select hitTest).ToDictionary(p => p.Set.ID.ToString() + ":" + p.Key.ID.ToString(),
                                                      p => p.YearHits);

                bundledData.intYear = intYear;
                bundledData.intMonth = intMonth;
                bundledData.intDay = intDay;
                bundledData.intHour = inthour;

                ViewBag.data = bundledData;
            }
            catch (Exception ex)
            {
                throw new Exception(infoExcepcion(ex));
            }
        }

        [Authorize]
        public ActionResult sessionStats()
        {
             if(Session["tmTracks"] == null)
                Session["tmTracks"] = new List<CTimeTrack>();

            return View(Session["tmTracks"]);
        }
    }
}